#pragma once
/*
 *  SBJ/NXT/CommandTypes.h
 *  NXTFace
 *
 *  Created by David Giovannini on 8/23/06.
 *  Copyright 2006 Software by Jove. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <limits>
#include <algorithm>
#include <string>

namespace SBJ
{

namespace NXT
{

#if defined( _INTEL_ )

inline char swap( char val ) { return val; }
inline unsigned char swap( unsigned char val ) { return val; }
inline short swap( short val ) { return val; }
inline unsigned short swap( unsigned short val ) { return val; }
inline long swap( long val ) { return val; }
inline unsigned long swap( unsigned long val ) { return val; }

#else

inline char swap( char val ) { return val; }
inline unsigned char swap( unsigned char val ) { return val; }
inline unsigned short swap( short val )
{
	std::swap( *(((char*)(&val))+0), *(((char*)(&val))+1) );
	return val;
}
inline short swap( unsigned short val ) { return SBJ::NXT::swap( (short) val ); }

inline unsigned long swap( long val )
{
	std::swap( *(((char*)(&val))+0), *(((char*)(&val))+3) );
	std::swap( *(((char*)(&val))+1), *(((char*)(&val))+2) );
	return val;
}
inline long swap( unsigned long val ) { return SBJ::NXT::swap( (long) val ); }

#endif

// Very important, we want fully packed structs
#pragma pack(1)

typedef char SBytes1;
typedef short SBytes2;
typedef long SBytes4;

typedef unsigned char UBytes1;
typedef unsigned short UBytes2;
typedef unsigned long UBytes4;

typedef char Empty[ 0 ];

template < typename base, base dft = base( 0 ) >
class Int
{
public:
	Int( void ) : m_val( dft ) {}
	
	Int( const base& val ) : m_val( swap( val ) ) {}
	
	Int& operator = ( const base& val ) { m_val = swap( val ); return *this; }
	
	operator base ( void ) const { return swap( m_val ); }
	
private:
	base m_val;
};

template < typename base, base min, base max, base dft = ((max+min)/2) >
class IntRange
{
public:
	static const base min_val = min;
	static const base max_val = max;
	
	IntRange( void ) : m_val( dft ) {}
	
	IntRange( const base& val ) : m_val( swap( val < min_val ? min_val : val > max_val ? max_val : val ) ) {}
	
	IntRange& operator = ( const base& val ) { m_val = swap( val < min_val ? min_val : val > max_val ? max_val : val ); return *this; }
	
	operator base ( void ) const { return swap( m_val ); }
	
	double getRatio( void ) const { return ( (double)swap( m_val ) ) / (double)(max_val-min_val); }
	
private:
	base m_val;
};

template < typename base, base dft = base( 0 ) >
class Enum
{
public:
	Enum( void ) : m_val( dft ) {}
	
	Enum( const base& val ) : m_val( swap( (unsigned char)val ) ) {}
	
	Enum& operator = ( const base& val ) { m_val = swap( (unsigned char)val ); return *this; }
	
	operator base ( void ) const { return (base)swap( m_val ); }
	
// Bit operations
	bool isFlagSet( const base& val )  const { return ( ( swap( m_val ) & val ) == val ); }
	
	Enum& setFlag( const base& val ) { m_val |= swap( (unsigned char)val ); return *this; }
	
	Enum& unsetFlag( const base& val ) { m_val &= ~swap( (unsigned char)val ); return *this; }
	
	bool setFlagTo( const base& val, bool state ) { return ( isFlagSet( val ) == state ? true : ( ( state ? setFlag( val ) : unsetFlag( val ), false ) ) ); }
	
private:
	unsigned char m_val;
};

class Bool
{
public:
	Bool( void ) : m_val( 0 ) {}
	
	Bool( bool val ) : m_val( val ? 1 : 0 ) {}
	
	Bool& operator = ( bool val ) { m_val = ( val ? 1 : 0 ); return *this; }
	
	operator bool ( void ) const { return ( m_val == 0 ? false : true ); }
	
private:
	Int< UBytes1 > m_val;
};

template < size_t size, size_t padding = 0 >
class Message
{
public:
	Message( void ) : m_size( 0 ) { m_data[ 0 ] = 0; }
	
	Message( const std::string& str ) : m_size( std::min( size, str.length() + 1 ) ) { ::strncpy( m_data, str.c_str(), m_size ); }
	
	Message( const char* str ) : m_size( std::min( size, ::strlen( str ) + 1 ) ) { ::strncpy( m_data, str, m_size ); }
	
	Message& operator = ( const std::string& str ) { m_size = std::min( size, str.length() + 1 ); ::strncpy( m_data, str.c_str(), m_size ); }
	
	Message& operator = ( const char* str ) { m_size = std::min( size, ::strlen( str ) + 1 ); ::strncpy( m_data, str, m_size ); }
	
	operator const char* ( void ) const { return m_data; }
	
	size_t getLength( void ) const { return ( m_size - 1 ); }
	
	size_t getSize( void ) const { return m_size; }
	
	static size_t getMaxSize( void ) { return size; }
	
private:
	UBytes1 m_size;
	char m_data[ size + padding ];
};

template < size_t size >
class String
{
public:
	String( void ) { m_data[ 0 ] = 0; }
	
	String( const std::string& str ) { ::strncpy( m_data, str.c_str(), size ); }
	
	String( const char* str ) { ::strncpy( m_data, str, size ); }
	
	String& operator = ( const std::string& str ) { ::strncpy( m_data, str.c_str(), size ); }
	
	String& operator = ( const char* str ) { ::strncpy( m_data, str, size ); }
	
	operator const char* ( void ) const { return m_data; }
	
	size_t getLength( void ) const { return ::strlen( m_data ); }
	
	size_t getSize( void ) const { return size; }
	
	static size_t getMaxSize( void ) { return size; }
	
private:
	char m_data[ size ];
};


#pragma pack()
}

}